#pragma once
#include "UltimatePhysXPrecompiled.h"
#include "UltimatePhysXScene.h"
#include "UltimatePhysXContactReport.h"

UltimatePhysXScene::UltimatePhysXScene(NxPhysicsSDK* physicsSDK,NxSceneDesc *sceneDesc)
{
	mPhysicsSDK = physicsSDK;
	mNxSceneDesc = sceneDesc;
}


UltimatePhysXScene::~UltimatePhysXScene(void)
{
	mPhysicsSDK->releaseScene(*mNxScene);

}

bool UltimatePhysXScene::initScene()
{
	mNxScene = mPhysicsSDK->createScene(*mNxSceneDesc);	
	if(!mNxScene)
	{ 
		mNxSceneDesc->simType = NX_SIMULATION_SW; 
		mNxScene = mPhysicsSDK->createScene(*mNxSceneDesc); 
		if(!mNxScene) return false;
	}


	mNxScene->setActorGroupPairFlags(2,3, NX_NOTIFY_ON_START_TOUCH);
	mNxScene->setActorGroupPairFlags(1,3, NX_NOTIFY_ON_START_TOUCH);
	mNxScene->setActorGroupPairFlags(3,1, NX_NOTIFY_ON_START_TOUCH);
	mNxScene->setActorGroupPairFlags(1,6, NX_NOTIFY_ON_START_TOUCH);
	mNxScene->setActorGroupPairFlags(6,1, NX_NOTIFY_ON_START_TOUCH);
	mNxScene->setActorGroupPairFlags(5,3, NX_NOTIFY_ON_START_TOUCH);
	mNxScene->setActorGroupPairFlags(3,5, NX_NOTIFY_ON_START_TOUCH);

	// Create the default material
	NxMaterial* defaultMaterial = mNxScene->getMaterialFromIndex(0); 
	defaultMaterial->setRestitution(0.5);
	defaultMaterial->setStaticFriction(0.5);
	defaultMaterial->setDynamicFriction(0.5);

	mNxScene->setUserContactReport(&physXContactReport);



	// No collision between the sword and its body
	mNxScene->setGroupCollisionFlag(1,1, false);
	// sword vs penguin
	mNxScene->setGroupCollisionFlag(1,2, false);
	// sword vs projectiles
	mNxScene->setGroupCollisionFlag(1,3, true);
	// sword vs enemies
	mNxScene->setGroupCollisionFlag(1,4, false);

	// penguins
	mNxScene->setGroupCollisionFlag(2,2, false);
	// penguin vs projectiles
	mNxScene->setGroupCollisionFlag(2,3, true);
	// penguin vs enemies
	mNxScene->setGroupCollisionFlag(2,4, false);

	// projectiles
	mNxScene->setGroupCollisionFlag(3,3, false);
	// projectiles vs enemies
	mNxScene->setGroupCollisionFlag(3,4, false);

	return true;
}
UltimatePhysicsActor * UltimatePhysXScene::createPhysicsActor(UltimatePhysicsActorDesc *desc,Ogre::Vector3 position, Ogre::Quaternion orientation, bool isKinematic, bool isStatic, int collisionGroup, int weight)
{

	UltimatePhysXActor * ultimateActor = new UltimatePhysXActor();
	NxActorDesc * actorDesc =((UltimatePhysXActorDesc*) desc)->getNxActorDesc();


	if (isStatic) 
		actorDesc->body = 0;
	else
		actorDesc->body = new NxBodyDesc();
	actorDesc->density = 10;
	actorDesc->globalPose.t 	= NxVec3(position.x,
				position.y,
				position.z);	
		
	bool valid = actorDesc->isValid();
	NxActor * actor = mNxScene->createActor(*actorDesc);


	actor->setGlobalOrientationQuat(NxQuat(NxVec3(orientation.x,orientation.y,orientation.z),orientation.w));
	if (isKinematic) actor->raiseBodyFlag(NX_BF_KINEMATIC);	//KINEMATIKUS ACTOR

	// Setting CollisionGroup
	actor->setGroup(collisionGroup);
	//Get all shapes of the actor
	NxShape*const* shapes = actor->getShapes();
	int nShapes = actor->getNbShapes();
	for (int i = 0; i <  nShapes; i++)
	{
		// Set the given group for all shapes
		shapes[i]->setGroup(collisionGroup);
	}

	ultimateActor->setNxActor(actor);
	actor->userData = ultimateActor;

	return (UltimatePhysicsActor*)ultimateActor;

}
UltimatePhysicsActorDesc * UltimatePhysXScene::createPhysicsActorDesc()
{
	return (UltimatePhysicsActorDesc*)new UltimatePhysXActorDesc();
}

void UltimatePhysXScene::destroyPhysicsActor(UltimatePhysicsActor* actor)
{
	NxActor * nxActor = ((UltimatePhysXActor*)actor)->getNxActor();
	actor->setUserData(NULL);
	mNxScene->releaseActor(*nxActor);
}

void UltimatePhysXScene::createPhysicsPlane(int height,int collisionGroup)
{
	NxPlaneShapeDesc planeDesc;
	planeDesc.d = height;
	planeDesc.group = collisionGroup;
	NxActorDesc actorDesc, actorDesc2;
	actorDesc.shapes.pushBack(&planeDesc);
	mNxScene->createActor(actorDesc);
	
}

void UltimatePhysXScene::setGravity(int x, int y, int z)
{
	mNxScene->setGravity(NxVec3(x,y,z));
}


void UltimatePhysXScene::stepSimulation(float elapsedTime)
{
	mNxScene->simulate(elapsedTime);
	mNxScene->flushStream();

	while (!mNxScene->fetchResults(NX_RIGID_BODY_FINISHED, false));
}


void UltimatePhysXScene::addContactListener(UltimatePhysicsContactListener* listener)
{
	physXContactReport.addContactListener(listener);
}